#ifndef _TWITTER_RESOURCE_OAUTH_H_
#define _TWITTER_RESOURCE_OAUTH_H_
#include "Object.h"
NS_BEGIN(Twit)
NS_BEGIN(Resource)
NS_BEGIN(OAuth)

typedef Object<bool> OPseudo;

class ObjectOAuth:public OPseudo
{
public:
	ObjectOAuth(IOAuth& o, const char* file):
	  OPseudo(o,"oauth",file,ReturnFormatOauth)
	{
		setVersion(0);
	}
};

/**
* @brief 
*  Allows a Consumer application to obtain an OAuth Request Token 
*  to request user authorization. 
*  This method fulfills Section 6.1 of the OAuth 1.0 authentication flow.
*  Please use HTTPS for this method, and all other OAuth token negotiation steps.
*  Usage Note: Only ASCII values are accepted for the oauth_nonce
*/
struct RequestToken:public ObjectOAuth
{
	RequestToken(IOAuth& o):ObjectOAuth(o,"request_token"){}

	/**
	* @param v
	*  Forces the user to enter their credentials to ensure the correct 
	*  users account is authorized.
	*  ex.) http://api.Twitter.com/OAuth/request_token.OAuth?force_login=true
	*/
	void setForceLogin(bool v)
	{
		setParam("force_login",v);
	}
};



/**
* @brief 
*  Allows a Consumer application to use an OAuth Request Token to request user authorization. 
*  This method fulfills Section 6.2 of the OAuth 1.0 authentication flow. 
*  Desktop applications must use this method (and cannot use OAuth/authenticate).
*  Please use HTTPS for this method, and all other OAuth token negotiation steps.
*  Usage Note: It is recommended you send the parameter oauth_callback for 
*  all application types. 
*  For desktop applications you can send oauth_callback=oob to force PIN-based desktop flow.
*/
struct Authorize:public ObjectOAuth
{
	Authorize(IOAuth& o):ObjectOAuth(o,"authorize"){}
};



/**
* @brief 
*  Allows a Consumer application to use an OAuth request_token to request user authorization.
*  This method is a replacement of Section 6.2 of the OAuth 1.0 authentication flow 
*  for applications using the Sign in with Twitter authentication flow. 
*  The method will use the currently logged in user as the account for 
*  access authorization unless the force_login parameter is set to true.
*  Please use HTTPS for this method, and all other OAuth token negotiation steps.
*/
struct Authenticate:public RequestToken
{
	Authenticate(IOAuth& o):RequestToken(o){ setFile("authenticate"); }
};



/**
* @brief 
*  Allows a Consumer application to exchange the OAuth Request Token for 
*  an OAuth Access Token. This method fulfills Section 6.3 of 
*  the OAuth 1.0 authentication flow
*  The OAuth access token may also be used for xAuth operations.
*  Please use HTTPS for this method, and all other OAuth token negotiation steps.
*/
struct AccessToken:public ObjectOAuth
{
	AccessToken(IOAuth& o):ObjectOAuth(o,"access_token"){};
	void set_xauth(std::string username, std::string password)
	{
		if(!username.empty() && !password.empty())
		{
			setParam("x_auth_username", username.c_str());
			setParam("x_auth_password", password.c_str());
			setParam("x_auth_mode","client_auth");
			setSchemeType(SchemeTypeHttps);
		}
		else
		{
			setParam("x_auth_username");
			setParam("x_auth_password");
			setParam("x_auth_mode");
			setSchemeType(SchemeTypeHttp);
		}
	}
};

NS_END;

struct XAuth
{
	virtual std::string getAccessToken(std::string& username, std::string& password, OUT std::string& token, OUT std::string& secret, OUT Value::UniqueID* userId=NULL)=0;
};

class COAuth:public XAuth
{
	friend class Twitter;
	CJKOauth& _o;
	COAuth(CJKOauth& o):access_token(o), authenticate(o), authorize(o), request_token(o),_o(o){}
	~COAuth(){};

	OAuthToken m_reqToken;
	OAuth::AccessToken access_token;
	OAuth::Authenticate authenticate;
	OAuth::Authorize   authorize;
	OAuth::RequestToken request_token;

	virtual std::string getAccessToken(std::string& username, std::string& password, OUT std::string& token, OUT std::string& secret, OUT Value::UniqueID* userId=NULL)
	{
		access_token.set_xauth(username, password);
		_o.setAccessToken(std::string(""),std::string(""));
		OAuthToken r = _o.requestAccessToken(access_token.getUri());
		token = r.token;
		secret = r.tokenSecret;
		_o.setAccessToken(token,secret);
		if(userId) *userId = Value::UniqueID(r.addtional["user_id"]);
		return r.addtional["screen_name"];
	}
public:
	std::string getUserAuthorizeUrl()
	{
		m_reqToken = _o.requestToken(request_token.getUri());
		return authorize.getUri() + std::string("?oauth_token=") + m_reqToken.token;
	}
	std::string getAccessToken(const char* pin, OUT std::string& token, OUT std::string& secret, OUT Value::UniqueID* userId=NULL)
	{
		return getAccessToken(std::string(pin), token, secret, userId);
	}
	std::string getAccessToken(std::string& pin, OUT std::string& token, OUT std::string& secret, OUT Value::UniqueID* userId=NULL)
	{
		access_token.set_xauth("","");
		OAuthToken r = _o.requestAccessToken(access_token.getUri(), m_reqToken.token, m_reqToken.tokenSecret, pin);
		token = r.token;
		secret = r.tokenSecret;
		_o.setAccessToken(token, secret);
		if(userId)  *userId = Value::UniqueID(r.addtional["user_id"]);
		return r.addtional["screen_name"];
	}
};

NS_END;
NS_END;

#endif /*_TWITTER_RESOURCE_OAUTH_H_*/